package site.wenneng.dev.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.wenneng.dev.common.util.MybatisUtils;
import site.wenneng.dev.service.BaseService;
import site.wenneng.dev.objs.bo.TaskUsedHoursBO;
import site.wenneng.dev.objs.po.WorkingHoursPO;
import site.wenneng.dev.objs.query.WorkingHoursRemoteQuery;
import site.wenneng.dev.objs.bo.WorkingHoursRemoteBO;
import site.wenneng.dev.dao.WorkingHoursMapper;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
@Slf4j
public class WorkingHoursService extends BaseService {

    private WorkingHoursMapper mapper;

    @SneakyThrows
    public WorkingHoursRemoteBO queryWorkingHoursFromRemoteSite(WorkingHoursRemoteQuery inDTO) {
        String payload = processRequest("req/working-hours.json.ftlh", inDTO);
        Request request = new Request.Builder()
                .url("https://finebi.hundsun.com/webroot/decision/v5/design/widget/data")
                .post(RequestBody.create(payload, MediaType.parse("application/json")))
                .build();
        ObjectMapper objectMapper = getObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(invoke(request));
        JsonNode codeNode = jsonNode.get("code");
        if (codeNode == null || !codeNode.textValue().equals("200")) {
            log.error("查询工时填报信息错误：{}", jsonNode.get("errorMsg").textValue());
            return null;
        }
        return objectMapper.readValue(jsonNode.get("data").traverse(), WorkingHoursRemoteBO.class);
    }

    public void syncWorkingHours(LocalDate start, LocalDate end) {
        int page = 1;
        WorkingHoursRemoteQuery inDTO = new WorkingHoursRemoteQuery(start, end, page);
        List<WorkingHoursPO> result = new ArrayList<>();
        while (true) {
            inDTO.setPage(page++);
            WorkingHoursRemoteBO workingHours = queryWorkingHoursFromRemoteSite(inDTO);
            if (workingHours == null) {
                break;
            }
            result.addAll(workingHours.toPOList());
        }
        proxy().overlaySave(start, end, result);
    }

    @Transactional
    public void overlaySave(LocalDate start, LocalDate end, List<WorkingHoursPO> result) {
        Wrapper<WorkingHoursPO> deleteWrapper = Wrappers.<WorkingHoursPO>lambdaQuery()
                .between(WorkingHoursPO::getWorkingDate, start, end);
        mapper.delete(deleteWrapper);
        MybatisUtils.saveBatch(WorkingHoursMapper.class, result);
    }

    public Map<String, BigDecimal> queryTaskUsedHours(List<String> taskIdList) {
        List<WorkingHoursPO> workingHoursPOList = mapper.selectList(Wrappers.query());
        Map<String, List<WorkingHoursPO>> collect = workingHoursPOList.stream()
                .collect(Collectors.groupingBy(WorkingHoursPO::getTaskId));
        return collect.entrySet().stream().map(entry -> {
            double sum = entry.getValue().stream().map(WorkingHoursPO::getWorkingHours).mapToDouble(BigDecimal::doubleValue).sum();
            return new TaskUsedHoursBO(entry.getKey(), BigDecimal.valueOf(sum));
        }).collect(Collectors.toMap(TaskUsedHoursBO::getTaskId, TaskUsedHoursBO::getWorkHours));
    }

    public List<WorkingHoursPO> queryRecordDuringThisWeek(LocalDate date) {
        LocalDate start = date.minusDays(date.getDayOfWeek().getValue() - 1);
        return queryRecordDuring(start, start.plusDays(7));
    }

    public List<WorkingHoursPO> queryRecordDuring(LocalDate begin, LocalDate end) {
        Wrapper<WorkingHoursPO> queryWrapper = Wrappers.<WorkingHoursPO>lambdaQuery()
                .between(WorkingHoursPO::getWorkingDate, begin, end);
        return mapper.selectList(queryWrapper);
    }

    public WorkingHoursService proxy() {
        return ((WorkingHoursService) AopContext.currentProxy());
    }
}
